// Copyright (C) 2024 Kumo inc.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//


#include <iterator>
#include <string>
#include <unordered_map>

#include <ktest/ktest.h>
#include <deneb/internal/last_accessed.h>

using namespace deneb::internal;

struct LastAccessedTest : public ::testing::Test {
  using Map = std::unordered_map<std::string, int>;
  static Map map;
};

// clang-format off
LastAccessedTest::Map LastAccessedTest::map = {
  {"one", 1},
  {"two", 2},
  {"three", 3}
};
// clang-format on

TEST_F(LastAccessedTest, IsAssignableFromConstAndNonConst) {
  auto front = map.find("one");

  LastAccessed<std::string, int> last_accessed(front->first, front->second);

  ASSERT_EQ(last_accessed.key(), "one");
  ASSERT_EQ(last_accessed.information(), 1);

  last_accessed = map.find("two");

  EXPECT_EQ(last_accessed.key(), "two");
  EXPECT_EQ(last_accessed.information(), 2);

  last_accessed = map.find("three");

  EXPECT_EQ(last_accessed.key(), "three");
  EXPECT_EQ(last_accessed.information(), 3);
}

TEST_F(LastAccessedTest, IsComparableWithConstAndNonConstIterators) {
  auto front = map.find("one");
  LastAccessed<std::string, int> last_accessed(front->first, front->second);

  // non-const
  EXPECT_EQ(last_accessed, front);
  EXPECT_EQ(front, last_accessed);

  EXPECT_NE(map.find("two"), last_accessed);
  EXPECT_NE(last_accessed, map.find("three"));

  // const
  Map::const_iterator const_front = map.find("one");
  EXPECT_EQ(last_accessed, const_front);
  EXPECT_EQ(const_front, last_accessed);

  Map::const_iterator iterator = map.find("two");
  EXPECT_NE(iterator, last_accessed);

  iterator = map.find("three");
  EXPECT_NE(last_accessed, iterator);
}

TEST_F(LastAccessedTest, IsComparableToConstAndNonConstKeys) {
  using namespace std::string_literals;

  std::string key = "forty-two";
  int information = 42;

  LastAccessed<std::string, int> last_accessed(key, information);

  EXPECT_EQ(last_accessed, key);
  EXPECT_EQ(key, last_accessed);

  EXPECT_EQ(last_accessed, "forty-two"s);
  EXPECT_EQ("forty-two"s, last_accessed);

  const std::string& key_const_reference = key;

  EXPECT_EQ(key_const_reference, last_accessed);
  EXPECT_EQ(last_accessed, key_const_reference);

  EXPECT_NE(last_accessed, "asdf"s);
  EXPECT_NE(last_accessed, "foo"s);
  EXPECT_NE(last_accessed, "forty-three"s);
}
